package co.yixiang.modules.monitoring.fluorite.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import co.yixiang.cache.Cache;
import co.yixiang.common.enums.ResultCode;
import co.yixiang.common.exception.ServiceException;
import co.yixiang.dozer.service.IGenerator;
import co.yixiang.modules.monitoring.entity.domain.Config;
import co.yixiang.modules.monitoring.fluorite.entity.FluoriteQueryForm;
import co.yixiang.modules.monitoring.fluorite.entity.dto.*;
import co.yixiang.modules.monitoring.fluorite.entity.enums.FluoriteApiEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class FluoriteServiceImpl implements FluoriteService{
    private static final String api = "https://open.ys7.com/api/lapp";
    private static final String cacheToken = "{FLUORITE}_AccessToken";
    @Autowired
    private Cache cache;
    @Autowired
    private IGenerator generator;

    @Autowired
    public Config config;// 配置文件bean

    @Override
    public List<DeviceDto> deviceList(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.DEVICE_LIST), stringObjectMap);
        final String data = verifyResult(result);
        final List<DeviceDto> convert = generator.convert(JSONUtil.parseArray(data), DeviceDto.class);
        return convert;
    }

    @Override
    public DeviceInfoDto deviceInfo(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.DEVICE_INFO), stringObjectMap);
        final String data = verifyResult(result);
        final DeviceInfoDto deviceInfoDto = JSONUtil.toBean(data, DeviceInfoDto.class);
        return deviceInfoDto;
    }

    @Override
    public String deviceStatusGet(FluoriteQueryForm queryForm) {
        return null;
    }
    @Override
    public List<CameraDto> deviceCameraList(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.DEVICE_LIST), stringObjectMap);
        final String data = verifyResult(result);
        final List<CameraDto> convert = generator.convert(JSONUtil.parseArray(data), CameraDto.class);
        return convert;
    }

    @Override
    public List<CameraDto> cameraList(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.CAMERA_LIST), stringObjectMap);
        final String data = verifyResult(result);
        final List<CameraDto> convert = generator.convert(JSONUtil.parseArray(data), CameraDto.class);
        return convert;
    }

    @Override
    public String deviceAdd(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.DEVICE_ADD), stringObjectMap);
        final String data = verifyResult(result);
        return data;
    }

    @Override
    public String deviceDelete(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.DEVICE_DELETE), stringObjectMap);
        final String data = verifyResult(result);
        return data;
    }

    @Override
    public String videoOpen(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.VIDEO_OPEN), stringObjectMap);
        final String data = verifyResult(result);
        return data;
    }

    @Override
    public String liveClose(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.VIDEO_CLOSE), stringObjectMap);
        final String data = verifyResult(result);
        return data;
    }

    @Override
    public DeviceLiveDto liveAddressV2(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.V2_LIVE_ADDRESS), stringObjectMap);
        final String data = verifyResult(result);
        final DeviceLiveDto deviceLiveDto = JSONUtil.toBean(data, DeviceLiveDto.class);
        return deviceLiveDto;
    }

    @Override
    public DeviceLiveV2Dto liveAddress(FluoriteQueryForm queryForm) {
        final String accessToken = getAccessToken();
        queryForm.setAccessToken(accessToken);
        final Map<String, Object> stringObjectMap = BeanUtil.beanToMap(queryForm);
        final String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.LIVE_ADDRESS), stringObjectMap);
        final String data = verifyResult(result);
        final List<DeviceLiveV2Dto> convert = generator.convert(JSONUtil.parseArray(data), DeviceLiveV2Dto.class);
        return CollectionUtil.isNotEmpty(convert) ? convert.get(0) : null;
    }

    /**
     * 获取萤石云 访问令牌
     * @return
     */
    @Override
    public String getAccessToken() {
        String accessToken = cache.getString(cacheToken);
        if (ObjectUtil.isEmpty(accessToken)) {
            // 请求萤石云，获取令牌
            // appKey | appSecret
            Map<String,Object> map = new HashMap<>();
            map.put("appKey",config.getFluoriteAppKey());
            map.put("appSecret",config.getFluoriteAppSecret());
            String result = HttpUtil.post(getReqUrl(FluoriteApiEnum.TOKEN_GET), map);
            // 验证请求是否成功
            final String data = verifyResult(result);

            final JSONObject jsonObject = JSONUtil.parseObj(data);
            accessToken = jsonObject.getStr("accessToken");
            cache.put(cacheToken,accessToken, 1000 * 60 * 24 * 7L);
        }
        return accessToken;
    }


    /**
     * 获取接口请求的 URL
     *
     * @param fluoriteApiEnum    {@link FluoriteApiEnum} 萤石云 API 接口枚举
     * @return {@link String} 返回完整的接口请求URL
     */
    public static String getReqUrl(FluoriteApiEnum fluoriteApiEnum) {
        String domain = api;
        return domain.concat(fluoriteApiEnum.getUrl());
    }

    /**
     * 验证请求之后返回的结果
     * @param result 返回体
     */
    public String verifyResult(String result) {
        if (ObjectUtil.isEmpty(result)) {
            throw new ServiceException(ResultCode.FLUORITE_RESULT_ERROR);
        }
        final JSONObject jsonObject = JSONUtil.parseObj(result);
        Integer code = jsonObject.getInt("code");
        String msg = jsonObject.getStr("msg");
        if (!code.equals(200)){
            throw new ServiceException(ResultCode.FLUORITE_RESULT_ERROR, msg);
        }
        return jsonObject.getStr("data");
    }


}
